home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / src / exampleCode / SciTex / examples / phong / trackball.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-02  |  13.1 KB  |  619 lines

  1. /******************************************************************************
  2.  *  trackball.c
  3.  ******************************************************************************
  4.  *
  5.  *  Purpose:
  6.  *      Descriptional text.
  7.  *
  8.  *  Authors:
  9.  *      Michael Teschner and Christian Henn
  10.  *
  11.  *  Note:
  12.  *      None.
  13.  *  
  14.  *  Revisions:
  15.  *      10.11.93    micha    Created file.
  16.  *
  17.  ******************************************************************************
  18.  *
  19.  *  COPYRIGHT (C)                  1992, 1993, 1994
  20.  *
  21.  *  BY  CHRISTIAN HENN             M.E. MUELLER-INSTITUTE FOR MICROSCOPY (MIM)
  22.  *      HENN@COMP.BIOZ.UNIBAS.CH   CH-4056 BASEL, SWITZERLAND   
  23.  *
  24.  *  AND MICHAEL WALDHERR-TESCHNER  SILICON GRAPHICS INDUSTRIES (SGI)
  25.  *      MICHA@BASEL.SGI.COM        CH-4125 RIEHEN, SWITZERLAND
  26.  *
  27.  ******************************************************************************
  28.  *
  29.  *  PERMISSION TO USE, COPY, MODIFY AND DISTRIBUTE THIS SOFTWARE AND ITS DOCU-
  30.  *  MENTATION FOR THE PURPOSE OF RESEARCH, DEVELOPMENT AND EDUCATION IS HEREBY
  31.  *  GRANTED FREE OF CHARGE, SUBJECT TO THE FOLLOWING RESTRICTIONS:
  32.  *
  33.  *  THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, EXPRESS,
  34.  *  IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF DESIGN,
  35.  *  MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR ARISING FROM A
  36.  *  COURSE OF DEALING, USAGE OR TRADE PRACTICE.
  37.  *
  38.  *  IN NO EVENT SHALL SILICON GRAPHICS OR THE M.E. MUELLER-INSTITUTE BE LIABLE
  39.  *  FOR ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
  40.  *  OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  41.  *  WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
  42.  *  LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
  43.  *  THIS SOFTWARE.
  44.  *
  45.  ******************************************************************************
  46.  */
  47. /*
  48.  *    Implementation of a virtual trackball.  See trackball.h for the
  49.  * interface to these routines.
  50.  *    Implemented by Gavin Bell, lots of ideas from Thant Tessman and
  51.  * the August '88 issue of Siggraph's "Computer Graphics," pp. 121-129.
  52.  */
  53. #include <stdio.h>
  54. #include <math.h>
  55. #include <device.h>
  56. #include "trackball.h"
  57.  
  58.  
  59. /*** michael teschner ***/
  60.  
  61. do_trackball()
  62. {
  63. int i;
  64.     pushmatrix();
  65.  
  66. /** trackball starts here */
  67.  
  68.         if( getbutton(LEFTMOUSE)) {
  69.             
  70.             nmx = getvaluator(MOUSEX);
  71.             nmy = getvaluator(MOUSEY);
  72.  
  73.  
  74.             if( nmx == omx && nmy == omy ) {
  75.         spr[0] = spr[1] = spr[2] = 0;
  76.         spr[3] = 1;
  77.                 popmatrix();
  78.                 return;
  79.             }
  80.         
  81.         
  82.         if( getbutton(LEFTSHIFTKEY) || getbutton(RIGHTSHIFTKEY) ){
  83.             if(getbutton(MIDDLEMOUSE)) {
  84.            g_tz -= (nmy-omy) / 20.0;
  85.            
  86.            }
  87.          else{
  88.            g_tx += (nmx - omx) /20.0;
  89.            g_ty += (nmy - omy) /20.0; 
  90.          }
  91.         goto lab;
  92.         }
  93.  
  94.             if( getbutton(MIDDLEMOUSE) ){
  95.         gr_sca = gr_sca - (nmy-omy)/100.0;
  96.         if( gr_sca < 0 ) gr_sca = 0.0;
  97.         omx = nmx; omy = nmy;
  98.         }
  99.         else{
  100.  
  101.         
  102.             u_to_wo(omx-w_ox, omy-w_oy, &p1x, &p1y);
  103.             u_to_wo(nmx-w_ox, nmy-w_oy, &p2x, &p2y);
  104.  
  105.             trackball( r, p1x, p1y, p2x, p2y);
  106.  
  107.  
  108.             loadmatrix(imat);
  109.  
  110.              rot(-r[0],'x'); rot(-r[1],'y'); rot(-r[2],'z');
  111.              multmatrix(mat);
  112.         
  113.             getmatrix(mat);
  114.  
  115.             loadmatrix(imat);
  116.  
  117.              multmatrix(rmat);
  118.              rot(r[0],'x'); rot(r[1],'y'); rot(r[2],'z');
  119.          
  120.             getmatrix(rmat);
  121.  
  122.        
  123.             for(i=0;i<4;i++) spr[i] = r[i];
  124.    lab:         
  125.             omx = nmx; omy = nmy;
  126.         }
  127.         }
  128.  
  129.        else{
  130. /*  no spinning - comment out the next 4 lines */
  131.             loadmatrix(imat);
  132.             rot(-spr[0],'x'); rot(-spr[1],'y'); rot(-spr[2],'z');
  133.         multmatrix(mat);
  134.             getmatrix(mat);
  135.             loadmatrix(imat);
  136.         multmatrix(rmat);
  137.             rot(spr[0],'x'); rot(spr[1],'y'); rot(spr[2],'z');
  138.             getmatrix(rmat);
  139.  
  140.             omx = getvaluator(MOUSEX);
  141.             omy = getvaluator(MOUSEY);
  142.         }
  143.  
  144.     popmatrix();
  145. } /* end do_trackball */
  146.  
  147. do_clipp()
  148. {
  149. int i;
  150.     pushmatrix();
  151.  
  152. /** trackball starts here */
  153.  
  154.         if( getbutton(LEFTMOUSE)) {
  155.             
  156.             nmx = getvaluator(MOUSEX);
  157.             nmy = getvaluator(MOUSEY);
  158.  
  159.  
  160.             if( nmx == omx && nmy == omy ) {
  161.         spr[0] = spr[1] = spr[2] = 0;
  162.         spr[3] = 1;
  163.                 popmatrix();
  164.                 return;
  165.             }
  166.         
  167.         
  168.         if( getbutton(LEFTSHIFTKEY) || getbutton(RIGHTSHIFTKEY) ){
  169.  
  170.            cp_tr -= (nmy - omy) /10.0; 
  171.            omx = nmx; omy = nmy;
  172.            popmatrix();
  173.            return;
  174.         }
  175.         
  176.         if( getbutton(DKEY) ){
  177.            cp_dt -= (nmy - omy) /10.0; 
  178.            omx = nmx; omy = nmy;
  179.            popmatrix();
  180.            return;
  181.         }
  182.       
  183.  
  184.  
  185.         
  186.             u_to_wo(omx-w_ox, omy-w_oy, &p1x, &p1y);
  187.             u_to_wo(nmx-w_ox, nmy-w_oy, &p2x, &p2y);
  188.  
  189.             trackball( r, p1x, p1y, p2x, p2y);
  190.  
  191.  
  192.             loadmatrix(imat);
  193.             cp_xr += r[0]*3;
  194.         cp_yr += r[1]*3;
  195.  
  196.             for(i=0;i<4;i++) spr[i] = r[i];       
  197.             omx = nmx; omy = nmy;
  198.        
  199.         }
  200.  
  201.        else{
  202. /*  no spinning - comment out the next 4 lines */
  203.           
  204.  
  205.             omx = getvaluator(MOUSEX);
  206.             omy = getvaluator(MOUSEY);
  207.         }
  208.  
  209.     popmatrix();
  210. } /* end do_clipp */
  211.  
  212.  
  213. sbr_ini_trackball(int id)
  214. {
  215.  
  216.     track_window = id;
  217.  
  218.     r[0] = r[1] = r[2] = 0.0;
  219.     r[3] = 1.0;
  220.         
  221.     spr[0] = spr[1] = spr[2] = 0.0;
  222.     spr[3] = 1.0;
  223.     
  224.     gr_sca = 1.0;
  225.  
  226.     get_win_par();
  227.     sbr_reset_mat();
  228.  
  229.  
  230. }
  231.  
  232. get_win_par()
  233. {
  234.     winset(track_window);
  235.     getsize( &w_xsiz, &w_ysiz);
  236.     getorigin(&w_ox, &w_oy);
  237.  
  238.     cx = (w_ox + w_xsiz/2.0);
  239.     cy = (w_oy + w_ysiz/2.0);
  240.  
  241. }
  242.  
  243. sbr_reset_cp()
  244. {
  245.     cp_xr = cp_yr = cp_tr = 0.0;
  246.     cp_dt = 2.0;
  247. }
  248. sbr_reset_mat()
  249. {
  250. int i, j;
  251.  
  252.     for(i=0;i<4;i++)
  253.       for(j=0;j<4;j++){
  254.     if( i == j ) imat[i][j] = mat[i][j] = rmat[i][j] = 1.0;
  255.     else         imat[i][j] = mat[i][j] = rmat[i][j] = 0.0;
  256.     }
  257.     
  258.     g_tx = g_ty = g_tz = 0.0;
  259. }
  260.  
  261. /* transformation from window-coordinates to world-coordinates */
  262. void u_to_wo(long sx, long sy, float *wx, float *wy)
  263. {
  264.    *wx = (2.0 * sx) / (float) w_xsiz - 1.0;
  265.    *wy = (2.0 * sy) / (float) w_ysiz - 1.0;
  266. }
  267.  
  268.  
  269. /*****   *******/
  270.  
  271. /* Size of virtual trackball, in relation to window size */
  272. float trackballsize = 0.4;
  273.  
  274. /* Function prototypes for local functions */
  275. float tb_project_to_sphere(float r, float x, float y);
  276. void normalize_euler(float *e);
  277.  
  278. /*
  279.  * Ok, simulate a track-ball.  Project the points onto the virtual
  280.  * trackball, then figure out the axis of rotation, which is the cross
  281.  * product of P1 P2 and O P1 (O is the center of the ball, 0,0,0)
  282.  * Note:  This is a deformed trackball-- is a trackball in the center,
  283.  * but is deformed into a hyperbolic solid of rotation away from the
  284.  * center.
  285.  * 
  286.  * It is assumed that the arguments to this routine are in the range
  287.  * (-1.0 ... 1.0)
  288.  */
  289. void trackball(float *e, float p1x, float p1y, float p2x, float p2y)
  290. {
  291.     float p1[3];
  292.     float p2[3];
  293.     float d[3];
  294.     float phi;    /* how much to rotate about axis */
  295.     float a[3];    /* Axis of rotation */
  296.         int i;    
  297.     vzero(a);
  298.     
  299.     if (p1x == p2x && p1y == p2y)
  300.     {
  301.         vzero(e);    /* Zero rotation */
  302.         e[3] = 1.0;
  303.         return ;
  304.     }
  305.  
  306. /*
  307.  * First, figure out z-coordinates for projection of P1 and P2 to
  308.  * deformed sphere
  309.  */
  310.     vset(p1, p1x, p1y, tb_project_to_sphere(trackballsize, p1x, p1y));
  311.     vset(p2, p2x, p2y, tb_project_to_sphere(trackballsize, p2x, p2y));
  312.  
  313. /*
  314.  *    Now, we want the cross product of P1 and P2
  315.  *  (Or cross product of p2 and p1... this was determined by trial and
  316.  * error, so there may be a compensating mathematical boo-boo
  317.  * somewhere else).
  318.  */
  319.  
  320.     vcross(p2, p1, a);
  321.     
  322. /*
  323.  *    Figure out how much to rotate around that axis.
  324.  */
  325.     vsub(p1, p2, d);
  326.     phi = fsin(vlength(d) / (2.0 * trackballsize));
  327.  
  328.     axis_to_euler(a, phi, e);
  329.  
  330.         for(i=0;i<3;i++) e[i] = e[i] * 180 / M_PI;
  331. }
  332.  
  333. /*
  334.  *    Given an axis and angle, compute euler paramaters
  335.  */
  336. void axis_to_euler(float *a, float phi, float *e)
  337. {
  338.     vnormal(a);    /* Normalize axis */
  339.     vcopy(a, e);
  340.     vscale(e, fsin(phi/2.0));
  341.     e[3] = fcos(phi/2.0);
  342. }
  343.  
  344. /*
  345.  * Project an x,y pair onto a sphere of radius r OR a hyperbolic sheet
  346.  * if we are away from the center of the sphere.
  347.  */
  348. float tb_project_to_sphere(float r, float x, float y)
  349. {
  350.     float d, t, z;
  351.  
  352.     d = sqrt(x*x + y*y);
  353.     if (d < r*M_SQRT1_2)    /* Inside sphere */
  354.     {
  355.         z = sqrt(r*r - d*d);
  356.     }
  357.     else    /* On hyperbola */
  358.     {
  359.         t = r / M_SQRT2;
  360.         z = t*t / d;
  361.     }
  362.     return z;
  363. }
  364.  
  365. /*
  366.  *    Given two rotations, e1 and e2, expressed as Euler paramaters,
  367.  * figure out the equivalent single rotation and stuff it into dest.
  368.  * 
  369.  * This routine also normalizes the result every COUNT times it is
  370.  * called, to keep error from creeping in.
  371.  */
  372. #define COUNT 100
  373. void add_eulers(float *e1, float *e2, float *dest)
  374. {
  375.     static int count=0;
  376.     register int i;
  377.     float t1[3], t2[3], t3[3];
  378.     float tf[4];
  379.  
  380.     vcopy(e1, t1); vscale(t1, e2[3]);
  381.     vcopy(e2, t2); vscale(t2, e1[3]);
  382.     vcross(e2, e1, t3);
  383.     vadd(t1, t2, tf);
  384.     vadd(t3, tf, tf);
  385.     tf[3] = e1[3] * e2[3] - vdot(e1, e2);
  386.  
  387.     for (i = 0 ; i < 4 ;i++)
  388.     {
  389.         dest[i] = tf[i];
  390.     }
  391.  
  392.     if (++count > COUNT)
  393.     {
  394.         count = 0;
  395.         normalize_euler(dest);
  396.     }
  397. }
  398.  
  399. /*
  400.  * Euler paramaters always obey:  a^2 + b^2 + c^2 + d^2 = 1.0
  401.  * We'll normalize based on this formula.  Also, normalize greatest
  402.  * component, to avoid problems that occur when the component we're
  403.  * normalizing gets close to zero (and the other components may add up
  404.  * to more than 1.0 because of rounding error).
  405.  */
  406. void normalize_euler(float *e)
  407. {    /* Normalize result */
  408.     int which, i;
  409.     float gr;
  410.  
  411.     which = 0;
  412.     gr = e[which];
  413.     for (i = 1 ; i < 4 ; i++)
  414.     {
  415.         if (fabs(e[i]) > fabs(gr))
  416.         {
  417.             gr = e[i];
  418.             which = i;
  419.         }
  420.     }
  421.  
  422.     e[which] = 0.0;
  423.  
  424.     e[which] = fsqrt(1.0 - (e[0]*e[0] + e[1]*e[1] +
  425.         e[2]*e[2] + e[3]*e[3]));
  426.  
  427.     /* Check to see if we need negative square root */
  428.     if (gr < 0.0)
  429.         e[which] = -e[which];
  430. }
  431.  
  432. /*
  433.  * Build a rotation matrix, given Euler paramaters.
  434.  */
  435. void build_rotmatrix(Matrix m, float *e)
  436. {
  437.     m[0][0] = 1 - 2.0 * (e[1] * e[1] + e[2] * e[2]);
  438.     m[0][1] = 2.0 * (e[0] * e[1] - e[2] * e[3]);
  439.     m[0][2] = 2.0 * (e[2] * e[0] + e[1] * e[3]);
  440.     m[0][3] = 0.0;
  441.  
  442.     m[1][0] = 2.0 * (e[0] * e[1] + e[2] * e[3]);
  443.     m[1][1] = 1 - 2.0 * (e[2] * e[2] + e[0] * e[0]);
  444.     m[1][2] = 2.0 * (e[1] * e[2] - e[0] * e[3]);
  445.     m[1][3] = 0.0;
  446.  
  447.     m[2][0] = 2.0 * (e[2] * e[0] - e[1] * e[3]);
  448.     m[2][1] = 2.0 * (e[1] * e[2] + e[0] * e[3]);
  449.     m[2][2] = 1 - 2.0 * (e[1] * e[1] + e[0] * e[0]);
  450.     m[2][3] = 0.0;
  451.  
  452.     m[3][0] = 0.0;
  453.     m[3][1] = 0.0;
  454.     m[3][2] = 0.0;
  455.     m[3][3] = 1.0;
  456. }
  457.  
  458. /** originally from the file vect.c **/
  459.  
  460. /*
  461.  * vect -
  462.  *    Various functions to support operations on vectors.
  463.  *
  464.  * David M. Ciemiewicz, Mark Grossman, Henry Moreton, and Paul Haeberli
  465.  *
  466.  * Modified for my own nefarious purposes-- Gavin Bell
  467.  *                     prototyping : pff
  468.  */
  469.  
  470. float *vnew(void)
  471. {
  472.     register float *v;
  473.  
  474.     v = (float *) malloc(sizeof(float)*3);
  475.     return v;
  476. }
  477.  
  478. float *vclone(float *v)
  479. {
  480.     register float *c;
  481.  
  482.     c = vnew();
  483.     vcopy(v, c);
  484.     return c;
  485. }
  486.  
  487. void vcopy(float *v1, float *v2)
  488. {
  489.     register int i;
  490.     for (i = 0 ; i < 3 ; i++)
  491.         v2[i] = v1[i];
  492. }
  493.  
  494. void vprint(float *v)
  495. {
  496.     printf("x: %f y: %f z: %f\n",v[0],v[1],v[2]);
  497. }
  498.  
  499. void vset(float *v, float x, float y, float z)
  500. {
  501.     v[0] = x;
  502.     v[1] = y;
  503.     v[2] = z;
  504. }
  505.  
  506. void vzero(float *v)
  507. {
  508.     v[0] = 0.0;
  509.     v[1] = 0.0;
  510.     v[2] = 0.0;
  511. }
  512.  
  513. void vnormal(float *v)
  514. {
  515.     vscale(v,1.0/vlength(v));
  516. }
  517.  
  518. float vlength(float *v)
  519. {
  520.     return fsqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
  521. }
  522.  
  523. void vscale(float *v, float div)
  524. {
  525.     v[0] *= div;
  526.     v[1] *= div;
  527.     v[2] *= div;
  528. }
  529.  
  530. void vmult(float *src1, float *src2, float *dst)
  531. {
  532.     dst[0] = src1[0] * src2[0];
  533.     dst[1] = src1[1] * src2[1];
  534.     dst[2] = src1[2] * src2[2];
  535. }
  536.  
  537. void vadd(float *src1, float *src2, float *dst)
  538. {
  539.     dst[0] = src1[0] + src2[0];
  540.     dst[1] = src1[1] + src2[1];
  541.     dst[2] = src1[2] + src2[2];
  542. }
  543.  
  544. void vsub(float *src1, float *src2, float *dst)
  545. {
  546.     dst[0] = src1[0] - src2[0];
  547.     dst[1] = src1[1] - src2[1];
  548.     dst[2] = src1[2] - src2[2];
  549. }
  550.  
  551. void vhalf(float *v1, float *v2, float *half)
  552. {
  553.     float len;
  554.  
  555.     vadd(v2,v1,half);
  556.     len = vlength(half);
  557.     if(len>0.0001)
  558.         vscale(half,1.0/len);
  559.     else
  560.         *half = *v1;
  561. }
  562.  
  563. float vdot(float *v1, float *v2)
  564. {
  565.     return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2];
  566. }
  567.  
  568. void vcross(float *v1, float *v2, float *cross)
  569. {
  570.     float temp[3];
  571.  
  572.     temp[0] = (v1[1] * v2[2]) - (v1[2] * v2[1]);
  573.     temp[1] = (v1[2] * v2[0]) - (v1[0] * v2[2]);
  574.     temp[2] = (v1[0] * v2[1]) - (v1[1] * v2[0]);
  575.     vcopy(temp, cross);
  576. }
  577.  
  578. void vdirection(float *v1, float *dir)
  579. {
  580.     *dir = *v1;
  581.     vnormal(dir);
  582. }
  583.  
  584. void vreflect(float *in, float *mirror, float *out)
  585. {
  586.     float temp[3];
  587.  
  588.     vcopy(mirror, temp);
  589.     vscale(temp,vdot(mirror,in));
  590.     vsub(temp,in,out);
  591.     vadd(temp,out,out);
  592. }
  593.  
  594. void vmultmatrix(float m1[][4], float m2[][4], float prod[][4])
  595. {
  596.     register int row, col;
  597.     float temp[4][4];
  598.  
  599.     for(row=0 ; row<4 ; row++) 
  600.         for(col=0 ; col<4 ; col++)
  601.             temp[row][col] = m1[row][0] * m2[0][col]
  602.                            + m1[row][1] * m2[1][col]
  603.                            + m1[row][2] * m2[2][col]
  604.                            + m1[row][3] * m2[3][col];
  605.     for(row=0 ; row<4 ; row++) 
  606.         for(col=0 ; col<4 ; col++)
  607.         prod[row][col] = temp[row][col];
  608. }
  609.  
  610. void vtransform(float *v, float mat[][4], float *vt)
  611. {
  612.     float t[3];
  613.  
  614.     t[0] = v[0]*mat[0][0] + v[1]*mat[1][0] + v[2]*mat[2][0] + mat[3][0];
  615.     t[1] = v[0]*mat[0][1] + v[1]*mat[1][1] + v[2]*mat[2][1] + mat[3][1];
  616.     t[2] = v[0]*mat[0][2] + v[1]*mat[1][2] + v[2]*mat[2][2] + mat[3][2];
  617.     vcopy(t, vt);
  618. }
  619.